"""
    TorrentBrowser plugin for XBMC
    Copyright (C) 2011-2012 Markus Langenoja
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    Function [TBBrowser]
    -------------------
    * getItems(params) - Depending on type of request sorts into the following
      three funcitons.
    * getFormatItems(params) - Gets the formats for specified movie ID. (Gazelle)
    * getSearchItems(params) - Get items by query
    * getPageItems(params) - Get items according to page in XBMC.
    * buildList(start,stop,items,position,itemList) - Builds a list of items from
      the raw data obtained from the torrent-site
    * getPositions(page,category) - Calculated where on the page items shall be parsed
      into the itemList by using current page in XBMC and the category which is currently
      browsed (most snatched etc.)
      
      THIS WHOLE MODULE NEEDS TO BE LOOKED OVER!!!
"""
import re, sys
import TBTools
        
class TBBrowser(TBTools.TBTools): 
    __web__ = sys.modules[ "__main__" ].__web__
    __info__ = sys.modules[ "__main__" ].__info__
    __deb__ = sys.modules[ "__main__" ].__deb__
    __plugin__ = sys.modules[ "__main__" ].__plugin__
    __settings__ = sys.modules[ "__main__" ].__settings__
    __scraper__ = sys.modules[ "__main__" ].__scraper__
    
    __torrents_per_page__ = __info__['TORRENTSPERPAGE']
    __items_per_page__ = [5,10,15,20,25,30][int(__settings__.getSetting('itemsperpage'))]      
    
    def getItems(self, params):
        """
        Takes page number from XBMC or movie-id to fetch a list of items to either be further parsed
        or send directly to xbmc to be downloaded.
        """
        get = params.get
        action = get('action')
        
        # If a pagenumber from XBMC is given, compute following branch
        if action == 'search':
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getItems:: Searching movies using query: ' + str(get('searchstring'))
                
            urlBase = self.__info__['SEARCH'].get('url') + str(get('searchstring'))
            # Build itemList
            return self.buildItemList(params,urlBase,searchChecks=True)
        
        elif action == 'get_formats':
            # If a torrent-id is given (currently only for PassThePopcorn), parse the page and return a dictionary
            # containing downloadUrl, Format, Filename and also if it is freeleech.      
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getItems:: Getting formats for movie-ID: ' + str(get('id'))
            
            return self.getFormatItems(params)
        
        elif action == 'get_movies':
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getItems:: Getting Movies from page: ' + str(get('page'))
            urlBase = self.__info__.get(get('category'))
            return self.buildItemList(params,urlBase)
        
        elif action == 'further_search':
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getItems:: Getting Movies from Query (%s) on Page: %s ' % (get('query'), get('page'))
            urlBase = self.__info__['SEARCH'].get('url') + str(get('query'))
            return self.buildItemList(params,urlBase)
            
        # If neither page nor id is given, return error.
        else:
            print 'ERROR: Did not give useful information to TBBrowser.getItems'
            return
        
    def getFormatItems(self,params):
        get = params.get
        
        # Initiate itemList dict.
        itemList = {}
        i = 0
        
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getFormatItems:: Running getFormats'
            
        if (not self.__info__['FORMATS']['formats']):
            # From TBSites, if site uses direct download from the movie-list, __info__['FORMATS']['formats'] would return False
            print self.__plugin__ + '::ERROR::TBBrowser::' + 'getFormatItems:: Something went wrong, site %s doesn\'t handle formats like gazelle' % self.__info__['SITE']
            return
        
        # Get data to parse the torrent-id page
        reget = self.__info__['FORMATS'].get
        url = reget('browseUrl') % (get('id'))
        regExp = reget('re')
        
        # Download and parse page using regexp
        raw = self.__web__.loginOpen(url)
        items = re.compile(regExp).findall(raw)
        
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getFormatItems:: Number of Items: ' + str(len(items))
        
        # Create dictionaries for each item containing information plus "freeleech" tag.
        for item in items:
            # Clean the dlstring and create the downloadurl
            url = self.__info__['BASEURL'] + '/' + self.replaceBadSigns(item[reget('dlurlindex')])
            # Cleans the Format-string from HTML tags and multi-spaces
            form = re.sub('<.+?>','',item[reget('formatindex')])
            form = re.sub('\s+',' ',form)
            # This sets the freeleech tag if found in format string, add it to begining of form (title)
            if re.search('.*[Ff]reeleech.*',item[reget('formatindex')]):
                form = '[FL] ' + form
            itemList[i] = {'folder':False,'downloadurl':url,'title':form,'filename':item[reget('filenameindex')],'scrape':False}
            i += 1
        
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getFormatItems:: itemList %s' % (itemList)
            
        return itemList
    
    def evaluateDetailsAndAddThemToItem(self, detailsRegEx, rawData, itemOutput):
        for curDetailRegEx in detailsRegEx:
                    
            if type(curDetailRegEx) == list:
                evaluatedList = []
                self.evaluateDetailsAndAddThemToItem(curDetailRegEx, rawData, evaluatedList)
                itemOutput.append(evaluatedList)
            else:
                res = re.compile(curDetailRegEx).search(rawData)
                if res: 
                    itemOutput.append(self.replaceBadSigns(res.group(1)))
                else:
                    itemOutput.append('')
    
    def tryToAddMoreInfoFromDetailsPage(self, scrapingFromDetailsPage, items):
        #We are going to try to scrape the more info for the items from the details page, 
        # because we can get more information from the it
        
        resultItems = items
        
        if (scrapingFromDetailsPage != None) and (scrapingFromDetailsPage != ''):        
            
            resultItems = []
            
            for itemCur in items:
                        
                itemCurList = list(itemCur)
                        
                rawTemp = self.__web__.loginOpen(scrapingFromDetailsPage + itemCur[0])
                                    
                self.evaluateDetailsAndAddThemToItem(self.__info__.get('DETAILSREGEXP'), rawTemp, itemCurList)                                            
                            
                resultItems.append(tuple(itemCurList))
            
            return resultItems
    
    def buildItemList(self,params,urlBase,searchChecks=False):
        get = params.get
        positions = self.getPositions(get('page'))
        regExp = self.__info__.get('REGEXP').get('re')
        pos = self.__info__.get('REGEXP').get('pos')
        scrapingFromDetailsPage = self.__info__.get('DETAILS')

        # Obtain data and build list of items containing (id, title, imdbid) in a dictionary for each item
        # Depending on if the "positions" return as a tuple, run over two pages, else just one
        if type(positions) == tuple:
            # If the first page isn't page 1, set both urls with addons from "getPositions"
            if positions[0]['addon']:
                url1 = urlBase+positions[0]['addon']
                url2 = urlBase+positions[1]['addon']
            else:
                url1 = urlBase
                url2 = urlBase+positions[1]['addon']
                
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'buildItemList:: Range of items reaches over two pages'
            raw1 = self.__web__.loginOpen(url1)
            
            if searchChecks:
                if self.searchCheck(params,raw1):
                    return
                
            raw2 = self.__web__.loginOpen(url2)
            items1 = re.compile(regExp).findall(raw1)
            items2 = re.compile(regExp).findall(raw2)            
                
            items1 = self.tryToAddMoreInfoFromDetailsPage(scrapingFromDetailsPage, items1)
            items2 = self.tryToAddMoreInfoFromDetailsPage(scrapingFromDetailsPage, items2)
            
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'buildItemList items1 and items2'
                print items1
                print items2
            
            itemList = self.buildList(positions[0]['start'], positions[0]['stop'], items1, pos)
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'buildItemList:: itemList page 1: \n %s' % (itemList)
            itemList = self.buildList(len(itemList)+positions[1]['start'], len(itemList)+positions[1]['stop'], items2, pos, itemList=itemList)
        else:
            if positions['addon']:
                url = urlBase+positions['addon']
            else:
                url = urlBase
            raw = self.__web__.loginOpen(url)
            if searchChecks:
                if self.searchCheck(params,raw):
                    return
            items = re.compile(regExp).findall(raw)
            
            items = self.tryToAddMoreInfoFromDetailsPage(scrapingFromDetailsPage, items)
                                
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'buildItemList items'
                print items
            
            itemList = self.buildList(positions['start'], positions['stop'], items, pos)
        
        return itemList
    
    def searchCheck(self,params,raw):
        get = params.get
        gets = self.__info__['SEARCH'].get
        # This searches the page using regexp matching site unique "Not found"
        if re.search(gets('re'),raw):
            ''' Call TBXbmc and show a OK dialog '''
            message = ['Sorry, nothing matched for', get('searchstring')]
            self.showOK('Nothing Found', message)
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'searchCheck:: No matches for query \'%s\'' % (get('searchstring'))
            return True
            
        # If the site redirects to the torrent site instead of showing results
        # this will check for it and rerun getItems with the torrent ID instead
        # Currently this is implemented purely with PassThePopcorn in mind.
        if gets('check'):
            if (not re.search(gets('check'),raw)):
                ''' If the search is a direct match, redo but with ID '''
                if self.__deb__:
                    print self.__plugin__ + '::DEBUG::TBBrowser::' + 'searchCheck:: Your query (%s) produced an exact match!' % (get('searchstring'))
                searchID = re.compile(gets('idregexp')).findall(raw)
                params = {'id':searchID[0],'action':'get_formats'}
                return self.getItems(params)
    
    def buildList(self, start, stop, items, pos, itemList={}):
        """
        Modulization for the page-part above. Builds a new itemList if non specified (default behaviour)
        and appends the itemList if specified.
        """
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'buildList:: start %s stop %s pos %s' % (start,stop,pos)
        for o in xrange(int(len(itemList)+start),int(len(itemList)+stop)):
            try:
                if self.__deb__:
                    print self.__plugin__ + '::DEBUG::TBBrowser::' + 'buildList:: building item %s of %s title: %s' % (o,len(items)-1,items[o][pos[1]])
                item = items[o]
                # If new list, set first value to 0 as the id-parsing part does.
                if len(itemList) == 1:
                    i = 0
                else:
                    i = len(itemList) +1
                # Start the list
                itemList[i] = {'id':item[pos[0]],'title':item[pos[1]],'scrape':True}
                
                # If the data contains an IMDB-ID, get this.
                if pos[2]:
                    itemList[i]['imdb'] = item[pos[2]]
                    
                # If the data contains the downloadUrl, provide it else provide isFolder
                if pos[3]:
                    itemList[i]['filename'] = item[pos[1]]
                    itemList[i]['downloadurl'] = self.__info__['BASEURL'] + '/' + self.replaceBadSigns(item[pos[3]])
                    itemList[i]['folder'] = False
                else:
                    itemList[i]['folder'] = True
                    
                #if the data contains the links to subtitles then provide them
                if pos[4]:
                    itemList[i]['subs'] = item[pos[4]]
                    
                #if the data contains link to magnet the provide its url
                if pos[5]:
                    itemList[i]['magneturl'] = self.replaceBadSigns(item[pos[5]])
            except: pass
                
        return itemList
    
    def getPositions(self,page):
        # Get basic browseUrl
        pageAddon = self.__info__['NEXTPAGE']['addon']
        adjustment = self.__info__['NEXTPAGE']['adj']
        
        # Sets correct number of items to show if settings are to high for site.
        if self.__items_per_page__ >= self.__torrents_per_page__:
            __nmbritems__ = self.__torrents_per_page__
        else:
            __nmbritems__ = self.__items_per_page__
            
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getPositions:: Adjusted shown number of Items: ' + str(__nmbritems__)
                    
        # Calculate positions using current XBMC-page and number of items showing per page in XBMC.
        endpos = int(page) * int(__nmbritems__)
        pos = int(endpos) - int(__nmbritems__)
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getPositions:: page %s pos %s endpos %s' % (page,pos,endpos)
        
        # Sets URL's appropriate to positions
        # If pos is within limits of first browser page
        if (pos >= 0) and (pos < self.__torrents_per_page__):
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getPositions:: On the first page' 
            firstAddon = None
            # If endpos isn't located on the first page, set the secondUrl to next page
            if (endpos / self.__torrents_per_page__ > 0) and endpos != self.__torrents_per_page__:
                if self.__deb__:
                    print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getPositions:: End on second page'
                secondAddon = pageAddon + str(2 + adjustment)
        else:
            # Decide which page number and adjust it according to TBSites, then set firstUrl.
            nr = pos/self.__torrents_per_page__
            pageNr = nr + 1 + adjustment
            firstAddon = pageAddon + str(pageNr)
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getPositions:: nr %s Pagenr %s firstAddon %s' % (nr,pageNr,firstAddon) 
            # If endpos isn't on the same page AND the modulus of endpos and __torrent_per_page__ 
            # isn't 0 (endpos being the last entry on page). Set secondPage to next url in place.
            if (endpos / self.__torrents_per_page__ > nr) and (endpos % self.__torrents_per_page__  != 0):
                secondAddon = pageAddon + str(pageNr + 1)
                
        # Instead of having sets of else inside the if/else clause above, set secondUrl to None if
        # it hasn't already been set.
        try:
            secondAddon
        except: secondAddon = None
        
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getPositions:: Items Starting Addon: %s Ending Addon: %s'  % (firstAddon,secondAddon)

        # Build tuple if secondUrl isn't None, first value being the first page and second value
        # being the second page.
        if secondAddon:
            positions = ({'addon':firstAddon,'start':pos % self.__torrents_per_page__,'stop':self.__torrents_per_page__},{'addon':secondAddon,'start':0,'stop':endpos % self.__torrents_per_page__})
        else:
            # If endpos is located at the end of the page, set it to end of page, otherwise
            # calculate where the end is.
            if (endpos % self.__torrents_per_page__ == 0):
                end = self.__torrents_per_page__
            else:
                end = endpos % self.__torrents_per_page__
            positions = {'addon':firstAddon,'start':pos % self.__torrents_per_page__,'stop':end}
                
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBBrowser::' + 'getPositions:: Positions:\n' + str(positions)
            
        return positions